package com.sunshine.wheel.study.netty.chat.server;

import com.sunshine.wheel.study.netty.chat.protocol.IMDecoder;
import com.sunshine.wheel.study.netty.chat.protocol.IMEncoder;
import com.sunshine.wheel.study.netty.chat.server.handler.HttpHandler;
import com.sunshine.wheel.study.netty.chat.server.handler.WebSocketHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;

/**
 * 聊天程序的服务端
 */
public class ChatServer {

    public static void main(String[] args) {
        final int port = 8090;
        run(port);
    }

    /**
     * 启动聊天程序服务端
     * @param port  端口号
     */
    private static void run(int port) {
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
        NioEventLoopGroup workerGroup = new NioEventLoopGroup(8);
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup).
                    channel(NioServerSocketChannel.class).
                    option(ChannelOption.SO_BACKLOG, 1024).
                    childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();

                            // 添加对自定义消息的编解码支持的handler
                            pipeline.addLast(new IMEncoder());
                            pipeline.addLast(new IMDecoder());

                            // 添加对HTTP协议支持的handler
                            // HttP消息解码器, 同时包含：HttpRequestDecoder, HttpResponseEncoder
                            pipeline.addLast(new HttpServerCodec());
                            // 将多个消息转换为单一的FullHttpRequest或者FullHttpResponse, 原因是HTTP解码器在每个HTTP消息中会生成多个消息对象
                            pipeline.addLast(new HttpObjectAggregator(64 * 1024));
                            // 支持异步发送大的码流(例如大的文件传输), 但不占用过多的内存，防止发生java内存溢出错误
                            pipeline.addLast(new ChunkedWriteHandler());
                            pipeline.addLast(new HttpHandler());

                            // 添加对WebSocket协议支持的handler
                            pipeline.addLast(new WebSocketServerProtocolHandler("/im"));
                            pipeline.addLast(new WebSocketHandler());
                        }
                    });
            ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

}
